//
// itertool - a polynormial and type-safe iterator framework in C++.
//
// Copyright (c) 2021-2025 Feng Cong
//
// Distributed under the MIT Software License
// See accompanying file LICENSE.txt or copy at
// https://opensource.org/licenses/MIT

#include <itertool/iter/adapter.h>

#include "itertool_test.h"

TEST_SUITE("Adapter") {
  const size_t kLimit = 10;

  struct MyIter1 {
    int value = 0;
    int start = 0;
    MyIter1() = default;
    explicit MyIter1(int val) : start(val) {}
  };

  struct Traits1 {
    using ItemType = int;
    static bool HasNext(MyIter1& it) { return it.value < kLimit; }
    static ItemType GetNow(MyIter1& it) { return it.value + it.start; }
    static void Advance(MyIter1& it) { ++it.value; }
  };

  TEST_CASE("Case when only the required methods are defined") {
    auto it = itertool::MakeIteratorAdapter<MyIter1, Traits1>();

    SUBCASE(
        "Methods such as IsFinite() should have fallback if not implemented by "
        "the user") {
      CHECK_FALSE(it.IsFinite());
      CHECK_FALSE(it.IsResetable());
      it.Reset();  // Nop.
      CHECK_EQ(0, it.LengthHint());
    }

    SUBCASE("The required methods such as HasNext() are forwarded correctly") {
      int i = 0;
      for (auto val : it) {
        CHECK_EQ(i, val);
        ++i;
      }
      CHECK_EQ(i, kLimit);
    }

    SUBCASE("Forwarding arguments to the wrapped object's constructor") {
      auto it = itertool::MakeIteratorAdapter<MyIter1, Traits1>(1);
      int i = 0;
      for (auto val : it) {
        CHECK_EQ(val, i + 1);
        ++i;
      }
    }
  }

#if 0
  TEST_CASE(
      "When Traits does not meet the requirements, compilation should fail") {
    struct SomeIter {};
    struct BadTraits {
      using ItemType = int;
      static bool HasNext(SomeIter&) { return false; }
      static void Advance(SomeIter&) {}
    };
    itertool::MakeIteratorAdapter<SomeIter, BadTraits>();
  }
#endif

}
